/*_SPShortDay = [Hai, Ba, Tu, Nam, Sau, Bay, CNN]
_SPDay = [Hai, Ba, Tu, Nam, Sau, Bay, CNN]
_SPShortMon = [Gieng, Hai]
_SPMon = []
_SPAMPM = [SA, CH];
*/
function SpDateEdit(clientName, textId, valueId, displayEffect, effectTime, effectStep, displayFormat, isEnable, isVisible, todayText, clearText) {
  var _util = Library.WebControl.Util;
  var _instance = this;
  var _isFirstShow = true;
  var _isEnable = isEnable;
  var _isVisible = isVisible;
  var _isMouseOver = false;
  var _textId = textId;
  var _ulMenuId = _textId + "ul";
  var _valueId = valueId;
  var _displayEffect = displayEffect;
  var _effectTime = effectTime;
  var _effectStep = effectStep;
  var _displayFormat = displayFormat;
  var _currentMonth = 0;
  var _currentYear = 1;
  var _currentText;
  var _todayText = todayText;
  var _clearText = clearText;
  var effectControl = null;
  var _dateChanged = null;
  var _hideComplete = null;
  window[clientName] = _instance;
  _globalHashObject.Add(clientName, _instance);

  function getTextControl() {
    return _util.GetObjectById(_textId);
  };


  function getValueControl() {
    return _util.GetObjectById(_valueId);
  };

  this.Enable = function() {
    if (arguments.length > 0) {
      _isEnable = arguments[0];
      var className = isEnable ? "spDateEdit" : "spDateEditDisable";
      var txt = getTextControl();
      _util.SetInputEnable(txt, _isEnable);
      _util.SetClass(txt.parentNode.parentNode, className);
    }
    return _isEnable;
  };

  this.Visible = function() {
    if (arguments.length > 0) {
      _isVisible = arguments[0];
      getTextControl().paretnNode.parentNode.style.display = isVisible ? "" : "none";
    }
    return _isVisible;
  };

  /*
  * Get the current day (javascript date) displayed in text box. if the text box is blank or displat wrong date, null is return
  */
  this.GetValue = function() {
    var value = getValueControl().value;

    if (value == null || value == '') {
      return null;
    }
    var s = value.split('|');
    return new Date(dateParseInt(s[0]), dateParseInt(s[1]), dateParseInt(s[2]), dateParseInt(s[3]), dateParseInt(s[4]), dateParseInt(s[5]));
    ;
  };

  function dateParseInt(text) {
    var value = trimZero(text);
    var number = parseInt(value);
    if (isNaN(number)) {
      return 0;
    }
    else {
      return number;
    }
  };
  /*
  * Set the date value for the date edit
  */
  this.SetValue = function(date) {
    var textControl = getTextControl();
    var valueControl = getValueControl();

    if (date == null || date == "") {
      textControl.value = "";
      textControl.value = "";
    }
    else {
      valueControl.value = date.getFullYear() + '|' + date.getMonth() + '|' + date.getDate() + '|' + date.getHours() + '|' + date.getMinutes() + '|' + date.getSeconds();
      textControl.value = formatDate(date, _displayFormat); // _instance.Format(date);
    }
  };
  /*
  * Get string with indicate formated
  * Example: the current date is: 12-22-2010 10:30:00, the client name is exampleDate;
  * <code>
  * 	exampleDate.ToString('yyyy') : display: 2010
  *  exampleDate.ToString('yyyy-hh'):display: 2010-10
  * </code>
  */
  this.ToString = function(format) {
    var date = _instance.GetValue();
    if (date == null) {
      return "";
    }
    return formatDate(date, format);

  };
  function formatDate(date, format) {
    var r = '';
    var y = date.getFullYear();
    var M = date.getMonth() + 1;
    var d = date.getDate();
    var h = date.getHours();
    var m = date.getMinutes();
    var s = date.getSeconds();
    var i = 0;
    while (i < format.length) {
      var tk = nextToken(format, i);
      i = tk[0];
      var t = tk[1];
      switch (t) {
        case 'dd':
          if (d < 10) {
            r += '0';
          }
        case 'd':
          r += d;
          break;
        case 'ddd':
          r += _SPShortDay[date.getDay()];
          break;
        case 'dddd':
          r += _SPDay[date.getDay()];
          break;
        case 'hh':
          if (h < 10) {
            r += '0';
          }
        case 'h':
          r += h % 12;
          break;
        case 'HH':
          if (h < 10) {
            r += '0';
          }
          break;
        case 'H':
          r += h;
          break;
        case 'mm':
          if (m < 10) {
            r += '0';
          }
        case 'm':
          r += m;
          break;
        case 'MM':
          if (M < 10) {
            r += '0';
          }
        case 'M':
          r += M;
          break;
        case 'MMM':
          r += _SPShortMon[M - 1];
          break;
        case 'MMMM':
          r += _SPMon[M - 1];
          break;
        case 'ss':
          if (s < 10) {
            r += '0';
          }
        case 's':
          r += s;
          break;
        case 't':
          if (h > 12) {
            r += _SPAMPM[1][0];
          }
          else {
            r += _SPAMPM[0][0];
          }
          break;
        case 'tt':
          if (h > 12) {
            r += _SPAMPM[1];
          }
          else {
            r += _SPAMPM[0];
          }
          break;
        case 'y':
          r += y[3];
          break;
        case 'yy':
          r += ('' + y).substring(2);
          break;
        case 'yyy':
        case 'yyyy':
          r += y;
          break;
        default:
          r += t;
      }
    }
    return r;
  };
  function initForFirstShow() {
    var ul = document.createElement('ul');
    ul.setAttribute('id', _ulMenuId);
    _util.SetClass(ul, "calendar");

    ul.onmouseout = function() {
      _isMouseOver = false;
    };

    ul.onmouseover = function() {
      _isMouseOver = true;
    };
    var textControl = getTextControl();
    textControl.parentNode.insertBefore(ul, textControl);
  };
  /*
  * Show the date edit form
  */
  this.Show = function() {
    if (!_isEnable || !_isVisible)
      return;
    if (_isFirstShow) {
      _isFirstShow = false;
      initForFirstShow();
    }
    var date = _instance.GetValue();
    if (date == null) {
      date = new Date();
    }

    render(date);

    //var xy = _util.GetRelativePosition(_textId);
    var divCalendar = _util.GetObjectById(_textId).parentNode.parentNode;
    var xy = _util.GetRelativePosition(divCalendar);
    var size = _util.GetSize(divCalendar);
    xy = [xy.X, xy.Y + size.H + 2];
    var ul = _util.GetObjectById(_ulMenuId);
    ul.style.left = xy[0] + 'px';
    ul.style.top = xy[1] + 'px';
    ul.style.zIndex = _util.GetMaxZindex() + 1; //_zIndex;
    if (effectControl == null) {
      effectControl = Library.WebControl.Effect.Create({
        Object: ul,
        Type: _displayEffect,
        Time: _effectTime,
        Step: _effectStep,
        ObjHeight: ul.clientHeight,
        ObjWidth: ul.clientWidth,
        Vision: 'V',
        HideComplete: function(s, e) {
          ul.style.zIndex = 0;
          ul.style.left = "-1000px";
          ul.style.top = "-1000px";
        }
      });
    }
    effectControl.Show();

    document.onmouseup = function(e) {
      if (!_isMouseOver) {
        var evt = _util.GetEvent(e);
        var o = evt.target ? evt.target : evt.srcElement;

        if (o.tagName.toUpperCase() != 'SELECT') {
          _instance.Hide();
        }

      }
      return true;
    };
  };
  this.Hide = function() {
    if (!effectControl) return;
    document.onmouseup = null;
    effectControl.Hide();
    if (_hideComplete != null)
      _hideComplete(_instance, {});
  };

  this.GetText = function() {
    return getTextControl().value;
  };

  function todayClick() {
    var d = new Date();
    dateClick(d.getFullYear(), d.getMonth(), d.getDate());
  };
  function clear() {
    var c = _instance.GetValue() != null;
    _instance.SetValue('');
    if (c) {
      if (_dateChanged != null) _dateChanged(_instance, {});
    }
    _instance.Hide();

  };

  function dateClick(year, month, day) {
    var oldDate = _instance.GetValue();
    _instance.SetValue(new Date(year, month, day));
    _instance.Hide();
    if (oldDate == null || oldDate.getDate() != day || oldDate.getMonth() != month || oldDate.getFullYear() != year) {
      // _instance.DateChanged(_instance, {});
      if (_dateChanged != null) _dateChanged(_instance, {});
    }
  };

  function render(date) {

    var dy = date.getDate();
    _currentMonth = date.getMonth();
    _currentYear = date.getFullYear();
    var ul = _util.GetObjectById(_ulMenuId);
    while (ul.childNodes.length > 0) {
      ul.removeChild(ul.childNodes.item(0));
    }
    var titleCalendar = createLi("title", "");
    ul.appendChild(titleCalendar);
    var spanMonth = createTag("span", "", _SPMon[_currentMonth]);
    spanMonth.onclick = function() {
      monthClick(this); //this is span at runtime            
    };
    titleCalendar.appendChild(spanMonth);
    var spanYear = createTag("span", "", _currentYear);
    spanYear.onclick = function() {
      yearClick(this);
    };
    titleCalendar.appendChild(spanYear);

    for (var i = 0; i < _SPShortDay.length; i++) {
      ul.appendChild(createLi("week", _SPShortDay[i]));
    }
    var fd = new Date(_currentYear, _currentMonth, 1).getDay();
    for (var i = 0; i < fd; i++) {
      ul.appendChild(createLi("blank", "&nbsp;"));
    }

    var now = new Date();
    var selectDate = _instance.GetValue();
    var td = 32 - new Date(_currentYear, _currentMonth, 32).getDate();
    for (var i = 1; i <= td; i++) {
      var li = createLi("day", "" + i);
      li.onclick = function() {
        dateClick(_currentYear, _currentMonth, parseInt(this.innerHTML)); //this is li
      };
      if (i == now.getDate() && _currentMonth == now.getMonth() && _currentYear == now.getFullYear()) {
        _util.SetClass(li, "today")
      }
      if (selectDate != null && selectDate.getFullYear() == _currentYear && selectDate.getMonth() == _currentMonth && selectDate.getDate() == i) {
        _util.SetClass(li, "select-day")
      }
      ul.appendChild(li);
    }
    var mLi = 7 - (fd + td) % 7;
    if (mLi < 7) {
      for (var i = 0; i < mLi; i++) {
        ul.appendChild(createLi("blank", "&nbsp;"));
      }
    }
    var bLi = createLi("cmdBar", "");
    var btn = createTag("div", "btnCmdToday", _todayText);
    btn.onclick = function() {
      todayClick();
    };
    bLi.appendChild(btn);
    btn = createTag("div", "btnCmdClear", _clearText);
    btn.onclick = function() {
      clear();
    };
    bLi.appendChild(btn);

    ul.appendChild(bLi);

  };
  function monthClick(span) {
    span.onclick = null;
    var selectElement = document.createElement("select");
    selectElement.onchange = function() {
      monthSelect(this); // this : is a select
    };

    selectElement.onblur = function() {
      monthSelect(this); //this : is a select
    };

    for (var i = 0; i < _SPMon.length; i++) {
      selectElement.options[i] = new Option(_SPMon[i], i);
      if (_currentMonth == i) {
        selectElement.selectedIndex = i;
      }
    }
    while (span.childNodes.length > 0) {
      span.removeChild(span.childNodes.item(0));
    }
    span.appendChild(selectElement);
    selectElement.focus();
  };
  function monthSelect(select) {
    var value = dateParseInt(select.value);
    var span = select.parentNode;
    span.innerHTML = _SPMon[value];
    span.onclick = function() {
      monthClick(this); //this is span
    };
    render(new Date(_currentYear, value, 1));
  };
  function yearClick(span) {
    span.onclick = null;
    while (span.childNodes.length > 0) {
      span.removeChild(span.childNodes.item(0));
    }
    var ip = document.createElement('input');
    ip.value = _currentYear;
    ip.setAttribute("style", "width:30px");
    ip.style.width = "30px";
    ip.onblur = function() {
      yearSelect(this); // this is input
    };
    ip.onkeypress = function(ev) {
      return _util.HandleEnterPress(ev, function() { yearSelect(this); });
      //var k = _util.GetKey(ev);
      //if (k == 13) {//enter key
      //yearSelect(this);
      //return false;
      //}
      //return true;
    };
    span.appendChild(ip);
    ip.focus();
  };
  function yearSelect(input) {
    var year = dateParseInt(input.value);
    if (year == 0) {
      year = _currentYear;
    }
    var span = input.parentNode;
    span.innerHTML = year;
    span.onclick = function() {
      yearClick(this);
    };
    render(new Date(year, _currentMonth, 1));
  };


  function createLi(clazz, text) {
    return createTag("li", clazz, text);
  };
  function createTag(tagName, clazz, text) {
    var tag = document.createElement(tagName);
    if (clazz != "") {
      _util.SetClass(tag, clazz);
    }
    tag.innerHTML = text;
    return tag;
  };


  function raiseTextChange() {
    var t = _instance.GetText();
    if (_currentText != t) {
      var d = _instance.ParseDate(t);
      if (isNaN(d.getFullYear()) || isNaN(d.getMonth()) || isNaN(d.getDate()))
        d = _instance.GetValue();
      _instance.SetValue(d);
    }
    _instance.Hide();
  };

  this.ParseDate = function(s) {
    if (s == null || s == "")
      return null;

    var d = {
      L: 0,
      I: -1,
      V: 0,
      T: 0
    };
    var m = {
      L: 0,
      I: -1,
      V: 0,
      T: 1
    };
    var y = {
      L: 0,
      I: -1,
      V: 0,
      T: 2
    };

    var days = new Array();
    var index = 0;
    var sp = [0, 0, 1];

    for (var i = 0; i < _displayFormat.length; i++) {
      if (index > 2)
        break;
      var c = _displayFormat.charAt(i);
      switch (c) {
        case 'd':
          d.L++;
          if (d.I == -1) {
            d.I = index;
            index++;
            days.push(d);
          }

          break;
        case 'M':
          m.L++;
          if (m.I == -1) {
            m.I = index;
            index++;
            days.push(m);
          }
          break;
        case 'y':
          y.L++;
          if (y.I == -1) {
            y.I = index;
            index++;
            days.push(y);
          }
          break;
        default:
          if (index == 0) {
            return null;
          }
          sp[index - 1] = 1;
          break;
      }
    }


    var str = "";
    var si = 0;
    for (var j = 0; j < days.length; j++) {
      var spl = sp[j];
      var ds = days[j];
      while (si < s.length) {
        var c = s.charAt(si);
        si++;

        if (isNaN(parseInt(c))) {
          var v = dateParseInt(str);
          if (isNaN(v))
            return null;
          ds.V = v;
          str = "";
          break;
        }
        else {
          str += c;
          if (spl == 0) {
            if (ds.L == str.length) {
              ds.V = dateParseInt(str);
              str = "";
              break;
            }
          }
        }

      }
      if (str.length > 0) {
        ds.V = dateParseInt(str);
      }
    }
    var dd = 1;
    var mm = 1;
    var yy = new Date().getFullYear();
    for (var i = 0; i < days.length; i++) {
      var _d = days[i];
      if (isNaN(_d.V)) continue;
      switch (_d.T) {
        case 0:
          dd = _d.V;
          break;
        case 1:
          mm = _d.V;
          break;
        case 2:
          yy = _d.V;
          break;
      }
    }
    return new Date(yy, mm - 1, dd, 0, 0, 0);
  };
  function nextToken(text, index) {
    var tk = '';
    var ex = 0; //1: expression, 2: literal
    var pc = ''; //preview char
    var hasQ = false;
    while (index < text.length) {
      var c = text.charAt(index);
      switch (c) {
        case 'd':
        case 'h':
        case 'H':
        case 'm':
        case 'M':
        case 's':
        case 't':
        case 'y':
          if (hasQ) {
            tk += c;
          }
          else
            if (ex != 2) {
            ex = 1;
            if (pc == c || pc == '') {
              tk += c;
            }
            else {
              return [index, tk];
            }
          }
          else {
            return [index, tk];
          }
          break;
        case '\'':
        case '"':
          if (!hasQ && ex == 1) {//first '						
            return [index, tk];
          }
          hasQ = !hasQ;
          if (ex != 1) {
            tk += c;
          }
          break;

        default:
          if (ex != 1) {
            tk += c;
            ex = 2;
          }
          else {
            return [index, tk];
          }
          break;
      }
      pc = c;
      index++;
    }

    return [index, tk];
  };


  function trimZero(text) {
    if (text == null || text == '') {
      return text;
    }
    var index = -1;
    for (var i = 0; i < text.length; i++) {
      if (text.charAt(i) == '0') {
        index = i + 1;
      }
      else {
        break;
      }
    }
    if (index == -1) {
      return text;
    }
    else {
      if (index >= text.length) {
        return '';
      }
      return text.substring(index);
    }
  };
  this.AddHandler = function(t, f) {
    switch (t) {
      case 1:
        _dateChanged = f;
        break;
      case 2:
        _hideComplete = f;
        break;
    }
  };
  this.Call = function(t, p) {
    switch (t) {
      case 1: //TextBlur
        if (!_isMouseOver)
          raiseTextChange();
        break;
      case 2: //TextClick
        _currentText = _instance.GetText();
        _instance.Show();
        break;
      case 3: //TextPress
        return _util.HandleEnterPress(p, function() { raiseTextChange(); });
    }
  };
};
